package com.zb.repository;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.zb.client.SkuFeignClient;
import com.zb.dto.SkuDTO;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Repository
public class SkuRepository {

    @Autowired
    private RestHighLevelClient client;
    @Autowired(required = false)
    private SkuFeignClient skuFeignClient;


    public Map<String, Object> search(Map<String, String> param) throws Exception {
        Map<String, Object> result = new HashMap<>();
        String keyword = param.get("keyword");
        Integer index = Integer.parseInt(param.get("index"));
        Integer size = Integer.parseInt(param.get("size"));
        if (keyword == null || "".equals(keyword)) {
            keyword = "手机";
        }

        SearchRequest searchRequest = new SearchRequest("tb_sku");
        searchRequest.types("doc");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.from((index - 1) * size);
        searchSourceBuilder.size(size);
        //条件查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.multiMatchQuery(keyword, "name"));
        if (!StringUtils.isEmpty(param.get("brand"))) {
            String[] split = param.get("brand").split(",");
            boolQueryBuilder.must(QueryBuilders.termsQuery("brand_name", split));
        }
        if (!StringUtils.isEmpty(param.get("cate"))) {
            boolQueryBuilder.must(QueryBuilders.termQuery("category_name", param.get("cate")));
        }
        for (String key : param.keySet()) {
            if (key.startsWith("spec_")) {
                String mapKey = key.substring(5);
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("specMap." + mapKey + ".keyword", param.get(key));
                boolQueryBuilder.must(termQueryBuilder);
            }
        }
        if (!Strings.isNullOrEmpty(param.get("price"))) {
            String[] prices = param.get("price").split("-");
            RangeQueryBuilder queryBuilder = null;
            if (!prices[0].equals("*") && !prices[1].equals("*")) {
                queryBuilder = QueryBuilders.rangeQuery("price").from(prices[0]).to(prices[1]);
            } else if (prices[0].equals("*")) {
                queryBuilder = QueryBuilders.rangeQuery("price").lte(prices[1]);
            } else {
                queryBuilder = QueryBuilders.rangeQuery("price").gte(prices[0]);
            }
            boolQueryBuilder.must(queryBuilder);
        }
        //添加排序规则
        if (!StringUtils.isEmpty(param.get("sortField")) && !StringUtils.isEmpty(param.get("sortRule"))) {
            String name = param.get("sortField");
            String rule = param.get("sortRule");
            searchSourceBuilder.sort(
                    new FieldSortBuilder(name)
                    .order(rule.equals("desc") ? SortOrder.DESC : SortOrder.ASC)
            );
        }

        //设置分组查询
        searchSourceBuilder
                .aggregation(AggregationBuilders.terms("brandGroup").field("brand_name").size(50));
        searchSourceBuilder
                .aggregation(AggregationBuilders.terms("cateGroup").field("category_name").size(50));
        searchSourceBuilder
                .aggregation(AggregationBuilders.terms("specGroup").field("spec").size(50));

        //添加关联信息
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        // 高亮配置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        highlightBuilder.preTags("<span style='coor:red;'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //执行请求获取响应
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        Terms brandTerms = response.getAggregations().get("brandGroup");
        Terms cateTerms = response.getAggregations().get("cateGroup");
        Terms specTerms = response.getAggregations().get("specGroup");

        List<Map<String, Object>> skuList = new ArrayList<>();
        SearchHit[] hits = response.getHits().getHits();
        long totalHits = response.getHits().getTotalHits();
        for (SearchHit hit : hits) {

            String id = hit.getId();
            Map<String, Object> data = hit.getSourceAsMap();
            data.put("id", id);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            String name = this.highLight(highlightFields, "name");
            if (!StringUtils.isEmpty(name)) {
                data.put("name", name);
            }
            skuList.add(data);
        }

        List<String> brandList = termsAsList(brandTerms);
        List<String> cateList = termsAsList(cateTerms);
        Map<String, Set<String>> specMap = termsAsMap(specTerms);
        result.put("brandList", brandList);
        result.put("cateList", cateList);
        result.put("specMap", specMap);
        result.put("skuList", skuList);
        result.put("totalHits", totalHits);
        return result;
    }

    private List<String> termsAsList(Terms terms) {
        List<String> list = new ArrayList<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            list.add(bucket.getKeyAsString());
        }
        return list;
    }

    private Map<String, Set<String>> termsAsMap(Terms terms) {
        Map<String, Set<String>> result = new HashMap<>();
        /**
         * {'尺寸': '4英寸'}
         * {'尺寸': '5英寸''颜色': '3GB+32GB'}
         * {'版本': '4GB+64GB'}
         * {'颜色': '故宫特别版', '版本': '10GB+256GB'}
         */
        List<String> specJsonList = this.termsAsList(terms);
        for (String json : specJsonList) {
            Map<String, String> jsonAsMap = JSON.parseObject(json, Map.class);
            for (Map.Entry<String, String> entry : jsonAsMap.entrySet()) {
                String key = entry.getKey(); //尺寸 //尺寸
                String value = entry.getValue();//4英寸 //5英寸
                Set<String> set = result.get(key);
                //验证是否第一次，添加这个key的信息
                if (set == null || set.size() <= 0) {
                    set = new HashSet<>();
                }
                set.add(value);
                result.put(key, set);
            }
        }
        return result;
    }


    private String highLight(Map<String, HighlightField> highlightFields, String field) {
        HighlightField highlightName = highlightFields.get(field);
        if (highlightName != null) {
            Text[] nameText = highlightName.fragments();
            StringBuffer names = new StringBuffer();
            for (Text name : nameText) {
                names.append(name.toString());
            }
            return names.toString();
        }
        return "";

    }


    public void importData() {
        for (int i = 1; i <= 1000; i++) {
            List<SkuDTO> list = skuFeignClient.page(i, 100);
            BulkRequest request = new BulkRequest();
            request.timeout("60m"); // 设置超时时间
            for (SkuDTO skuDTO : list) {
                Map<String, Object> jsonMap = new HashMap<>();
                jsonMap.put("sn", skuDTO.getSn());
                jsonMap.put("name", skuDTO.getName());
                jsonMap.put("price", skuDTO.getPrice());
                jsonMap.put("num", skuDTO.getNum());
                jsonMap.put("alert_num", skuDTO.getAlertNum());
                jsonMap.put("image", skuDTO.getImage());
                jsonMap.put("images", skuDTO.getImages());
                jsonMap.put("weight", skuDTO.getWeight());
                jsonMap.put("spu_id", skuDTO.getSpuId());
                jsonMap.put("category_id", skuDTO.getCategoryId());
                jsonMap.put("category_name", skuDTO.getCategoryName());

                jsonMap.put("brand_name", skuDTO.getBrandName());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                jsonMap.put("create_time", sdf.format(skuDTO.getCreateTime()));
                jsonMap.put("update_time", sdf.format(skuDTO.getUpdateTime()));
                jsonMap.put("spec", skuDTO.getSpec());
                jsonMap.put("sale_num", skuDTO.getSaleNum());
                jsonMap.put("comment_num", skuDTO.getCommentNum());
                jsonMap.put("status", skuDTO.getStatus());
                jsonMap.put("version", skuDTO.getVersion());
                String specJSON = skuDTO.getSpec();
                jsonMap.put("specMap", JSON.parseObject(specJSON, Map.class));
                request.add(new IndexRequest("tb_sku", "doc", skuDTO.getId()).source(jsonMap));
            }
            try {
                BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
                System.out.println(response.buildFailureMessage());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void createIndex() {
        CreateIndexRequest request = new CreateIndexRequest(
                "tb_sku", Settings.builder()
                .put("number_of_shards", "1")
                .put("number_of_replicas", 0).build());

        request.mapping("doc", "{\n" +
                "\t\"properties\": {\n" +
                "\t\t\"sn\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"name\": {\n" +
                "\t\t\t\"type\": \"text\",\n" +
                "\t\t\t\"analyzer\": \"ik_max_word\",\n" +
                "\t\t\t\"search_analyzer\": \"ik_smart\"\n" +
                "\t\t},\n" +
                "\t\t\"price\": {\n" +
                "\t\t\t\"type\": \"float\"\n" +
                "\t\t},\n" +
                "\t\t\"num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"alert_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"image\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"images\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"weight\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"create_time\": {\n" +
                "\t\t\t\"type\": \"date\",\n" +
                "\t\t\t\"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd\"\n" +
                "\t\t},\n" +
                "\t\t\"update_time\": {\n" +
                "\t\t\t\"type\": \"date\",\n" +
                "\t\t\t\"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd\"\n" +
                "\t\t},\n" +
                "\t\t\"spu_id\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"category_id\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"category_name\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"brand_name\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"spec\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"sale_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"comment_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"status\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"version\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"specMap\":{\n" +
                "               \"properties\":{\n" +
                "                   \"test\":{\n" +
                "                       \"type\": \"keyword\"\n" +
                "}\n" +
                "}\n" +
                "\t\t}\n" +
                "\t}\n" +
                "}", XContentType.JSON);

        try {
            CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
            System.out.println(response.isAcknowledged());
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    public static void main(String[] args) {
        String str = "小米";
        String[] split = str.split(",");
        System.out.println(Arrays.toString(split));
    }
}
